package com.salinity.kun.task;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

import com.salinity.kun.helper.BaseHydrologyDataHelper;
import com.salinity.kun.helper.CalculationHelper;
import com.salinity.kun.helper.ConstantHelper;
import com.salinity.kun.helper.FourierSeriesHelper;
import com.salinity.kun.helper.OracleHelper;
import com.salinity.kun.model.FourierSeriesInput;
import com.salinity.kun.model.StationDateData;
import com.salinity.kun.model.Tides;
import com.salinity.kun.util.DateUtil;
import com.salinity.kun.util.PathUtil;

public class ZhenJiangFSTask implements ITask {

	public ZhenJiangFSTask() {
	}

	@Override
	public boolean run() throws IOException, ParseException {

		int interval = 5;
		String dateStr = "2018/06/1 0:0:0";
		String stationID = "2c9240214f50ba3a0150655a06be000c";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Path outputPath = Paths.get("E:\\Kuner\\BYLW\\Jworkspace\\saltyCode\\test\\");
		int shortInterval = 1;
		Date SDate = sdf.parse(dateStr);

		try {
			doFs(stationID, SDate, interval, shortInterval, sdf, outputPath);
		} catch (SQLException e) {
			e.printStackTrace();
		}

		return true;
	}

	public boolean doFs(String stationID, Date SDate, int interval, int shortInterval, SimpleDateFormat sdf,
			Path outputPath) throws ParseException, IOException, SQLException {
		doFs(stationID, SDate, interval, shortInterval, sdf, outputPath, true);
		return true;
	}

	public boolean doFs(String stationID, Date SDate, int interval, int shortInterval, SimpleDateFormat sdf,
			Path outputPath, boolean needCompare) throws ParseException, IOException, SQLException {

		long duration = 0;
		LocalDateTime LDTime = null;
		ResultSet rsltSet = null;
		List<StationDateData> tideList = null;
		Tides[] tides = Tides.values();
		int compareSeriesCount = 20;
		String[] itemArray = ConstantHelper.getOutputItems();

		// prepare DB connection
		OracleHelper oracleHelper = new OracleHelper();
		oracleHelper.prepareTideSQL();
		StringBuilder sb = null;
		Path compareAllRsltPath = null;
		if(needCompare) {
			compareAllRsltPath = outputPath.resolve("all_compare.csv");
			PathUtil.preparePath(compareAllRsltPath);
		}
		
		
		for (Tides tide : tides) {
			LDTime = DateUtil.Date2LDTime(SDate);
			duration = (long) tide.getVal(interval);
			Date EDate = DateUtil.LDTime2Date(LDTime.plusMinutes(duration));

			// print info
			System.out.println(
					"Processing " + tide.name() + "(T:" + tide.getVal() + " min, Round T:" + duration + " min) ...");
			System.out.println("From " + sdf.format(SDate) + " to " + sdf.format(EDate));
			System.out.println();

			// do query
			rsltSet = oracleHelper.doTideQuery(SDate, EDate, stationID);
			if (rsltSet == null) {
				System.out.println("query result is null.");
				return false;
			}
			tideList = oracleHelper.parseRslt(rsltSet);

			// linear interpolation
			List<StationDateData> linearInTideList = BaseHydrologyDataHelper.doLinearInterpolation(tideList, SDate,
					EDate, interval);

			// Save linear Fourier series result to file
			FourierSeriesInput beforeFsi = BaseHydrologyDataHelper.hydToFsi(linearInTideList, interval);
			CalculationHelper.writeToFile(beforeFsi, itemArray,
					outputPath.resolve(tide.name() + "_" + interval + ".csv"));

			// More dense interpolation
			List<StationDateData> denseInTideList = BaseHydrologyDataHelper
					.doProportionalInterpolation(linearInTideList, interval, interval / shortInterval);

			// Save to file
			FourierSeriesInput denseFsi = BaseHydrologyDataHelper.hydToFsi(denseInTideList, shortInterval);
			CalculationHelper.writeToFile(denseFsi, itemArray,
					outputPath.resolve(tide.name() + "_" + shortInterval + ".csv"));

			if (needCompare) {
				sb = compareFourierSeriesResult(tide.name(),beforeFsi, denseFsi, compareSeriesCount);
				if (sb != null) {
					Path compareRsltPath = outputPath.resolve(tide.name() + "_compare.csv");
					PathUtil.preparePath(compareRsltPath);
					try (BufferedWriter bw = Files.newBufferedWriter(compareRsltPath)) {
						bw.write(sb.toString());
					}
					//汇总所有的比较结果
					sb.append("\n\n\n");
					try (BufferedWriter bw = Files.newBufferedWriter(compareAllRsltPath,StandardOpenOption.APPEND)) {
						bw.write(sb.toString());
					}
				}
				
				
				
			}
		}
		System.out.println("All done.");

		// end connection
		oracleHelper.end();
		return true;
	}

	/**
	 * 加密插值前后所得傅里叶级数相比较,存成单个文件，返回所存内容
	 * 
	 * @param beforeDenseInTideList
	 *            加密前的水位数据
	 * @param denseInTideList
	 *            加密后的水位数据
	 * @param outputPath
	 *            输出文件夹
	 * @param tideName
	 *            用于保存文件的命名
	 */
	private StringBuilder compareFourierSeriesResult(String tideName,FourierSeriesInput beforeFsi, FourierSeriesInput denseFsi,
			int compareSeriesCount) {
		StringBuilder sb = new StringBuilder();
		if (compareSeriesCount < 0 || compareSeriesCount > beforeFsi.getSeriesCount()
				|| compareSeriesCount > denseFsi.getSeriesCount()) {
			System.out.println("Compare count can not more than series count.Save compare result failure.");
			return sb;
		}
		FourierSeriesHelper beforeFsh = new FourierSeriesHelper(beforeFsi);
		FourierSeriesHelper denseFsh = new FourierSeriesHelper(denseFsi);
		sb.append(tideName).append("\n");
		sb.append("sn").append(",").append("before").append(",").append("dense").append("\n");
		for (int i = 0; i < compareSeriesCount; i++) {
			sb.append(i).append(",").append(beforeFsh.get_fs(i)).append(",").append(denseFsh.get_fs(i));
			if (i < compareSeriesCount - 1) {
				sb.append("\n");
			}
		}
		return sb;
	}

	public static void main(String[] args) {
		ITask zhenJiangFSTask = new ZhenJiangFSTask();

		try {
			zhenJiangFSTask.run();
		} catch (IOException | ParseException e) {
			e.printStackTrace();
		}
	}
}
